package com.flyqiu.flow.core.tools;

import com.flyqiu.flow.bpmn.base.BaseProcElementNode;
import com.flyqiu.flow.bpmn.base.ScriptModel;
import com.flyqiu.flow.bpmn.element.EndEvent;
import com.flyqiu.flow.bpmn.element.ProcessModel;
import com.flyqiu.flow.bpmn.element.SequenceFlow;
import io.swagger.v3.oas.annotations.media.Schema;
import com.flyqiu.flow.api.script.FlyQiuFlowScriptActuatorManage;
import com.flyqiu.flow.api.script.IVariableScope;
import com.flyqiu.flow.bpmn.element.BaseProcElement;


import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 流程顺序计算
 */
public record ProcSequenceCompute(@Schema(title = "下一顺序活动") List<SequenceFlow> nextLines,
                                  @Schema(title = "默认顺序活动") SequenceFlow defaultSequenceFlow) {
    public ProcSequenceCompute(List<SequenceFlow> nextLines, SequenceFlow defaultSequenceFlow) {
        this.nextLines = nextLines;
        this.defaultSequenceFlow = defaultSequenceFlow;
    }

    public SequenceFlow getFinalSingle() {
        if (nextLines != null && !nextLines.isEmpty()) {
            return nextLines.get(0);
        }
        return defaultSequenceFlow;
    }

    public List<SequenceFlow> getFinalMultiple(boolean addDefault) {
        if (nextLines != null && !nextLines.isEmpty()) {
            return nextLines;
        }
        List<SequenceFlow> result = new ArrayList<>();
        if (!addDefault) {
            return result;
        }
        if (defaultSequenceFlow == null) {
            return result;
        }
        result.add(defaultSequenceFlow);
        return result;
    }

    /**
     * 计算流程下一活动
     *
     * @param scriptManage  脚本管理器
     * @param processModel  流程模型
     * @param curDefKey     当前所处流程活动定义
     * @param variableScope 流程变量
     * @return ProcSequenceCompute
     */
    public static ProcSequenceCompute compute(FlyQiuFlowScriptActuatorManage scriptManage, ProcessModel processModel, String curDefKey, IVariableScope variableScope) {
        BaseProcElement currentElement = processModel.getElement(curDefKey);
        if (currentElement == null) {
            return new ProcSequenceCompute(null, null);
        }
        if (currentElement instanceof EndEvent) {
            return new ProcSequenceCompute(null, null);
        }
        BaseProcElementNode currentNode = (BaseProcElementNode) currentElement;
        return compute(scriptManage, currentNode, variableScope);
    }

    /**
     * 计算流程下一活动
     *
     * @param scriptManage  脚本执行管理
     * @param currentNode   当前环节
     * @param variableScope 遍历
     * @return ProcSequenceCompute
     */

    public static ProcSequenceCompute compute(FlyQiuFlowScriptActuatorManage scriptManage, BaseProcElementNode currentNode, IVariableScope variableScope) {
        List<SequenceFlow> outSequenceFlows = currentNode.getOutgoingFlows();
        List<SequenceFlow> sequenceFlows = new ArrayList<>();
        String defaultTargetKey = currentNode.getDefaultTargetKey();
        Optional<SequenceFlow> first = outSequenceFlows.stream().filter(e -> e.getDefKey().equals(defaultTargetKey)).findFirst();
        SequenceFlow defaultSequenceFlow = null;
        if (first.isPresent()) {
            defaultSequenceFlow = first.get();
        }
        for (SequenceFlow sequenceFlow : outSequenceFlows) {
            BaseProcElement targetNode = sequenceFlow.getTargetNode();
            if (targetNode == null) {
                continue;
            }
            List<ScriptModel> conditionalExpression = sequenceFlow.getConditionalExpression();
            if (conditionalExpression == null || conditionalExpression.isEmpty()) {
                sequenceFlows.add(sequenceFlow);
                continue;
            }
            if (scriptManage.executeBooleanHasTrue(conditionalExpression, variableScope)) {
                sequenceFlows.add(sequenceFlow);
            }
        }
        return new ProcSequenceCompute(sequenceFlows, defaultSequenceFlow);
    }

}
